From 17fe9ee2ccd7dfefb78f74b04ab3a75979657dac Mon Sep 17 00:00:00 2001 From: alexmot Date: Mon, 5 Jan 2004 15:47:33 +0000 Subject: [PATCH] Move OziExplorer into it's own module. Adds track/route read/write support for Ozi. --- gpsbabel/Makefile | 5 +- gpsbabel/internal_styles.c | 52 +--- gpsbabel/ozi.c | 618 +++++++++++++++++++++++++++++++++++++ gpsbabel/vecs.c | 7 + 4 files changed, 629 insertions(+), 53 deletions(-) create mode 100644 gpsbabel/ozi.c diff --git a/gpsbabel/Makefile b/gpsbabel/Makefile index b391a4bdb..40eb1dbe1 100644 --- a/gpsbabel/Makefile +++ b/gpsbabel/Makefile @@ -18,7 +18,8 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o \ gpsutil.o pcx.o cetus.o copilot.o gpspilot.o magnav.o \ psp.o holux.o garmin.o tmpro.o tpg.o \ xcsv.o gcdb.o tiger.o internal_styles.o easygps.o quovadis.o \ - gpilots.o saroute.o navicache.o psitrex.o geoniche.o delgpl.o + gpilots.o saroute.o navicache.o psitrex.o geoniche.o delgpl.o \ + ozi.o FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o reverse_route.o @@ -211,5 +212,5 @@ jeeps/gpsutil.o: jeeps/gpsutil.c jeeps/gps.h jeeps/gpsport.h \ jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ jeeps/gpsmath.h jeeps/gpsnmea.h jeeps/gpsmem.h jeeps/gpsrqst.h \ jeeps/gpsinput.h jeeps/gpsproj.h jeeps/gpsnmeafmt.h jeeps/gpsnmeaget.h -internal_styles.c: mkstyle.sh style/README.style style/arc.style style/csv.style style/custom.style style/dna.style style/fugawi.style style/gpsdrive.style style/gpsman.style style/mapconverter.style style/mxf.style style/nima.style style/ozi.style style/s_and_t.style style/tabsep.style style/xmap.style style/xmapwpt.style +internal_styles.c: mkstyle.sh style/README.style style/arc.style style/csv.style style/custom.style style/dna.style style/fugawi.style style/gpsdrive.style style/gpsman.style style/mapconverter.style style/mxf.style style/nima.style style/s_and_t.style style/tabsep.style style/xmap.style style/xmapwpt.style ./mkstyle.sh > $@ || (rm -f $@ ; exit 1) diff --git a/gpsbabel/internal_styles.c b/gpsbabel/internal_styles.c index 9bc065bfa..93accec7f 100644 --- a/gpsbabel/internal_styles.c +++ b/gpsbabel/internal_styles.c @@ -368,56 +368,6 @@ static char nima[] = "IFIELD DESCRIPTION, \"\", \"%s\" # FULL_NAME_ND\n" "IFIELD IGNORE, \"\", \"%s\" # MODIFY_DATE\n" ; -static char ozi[] = -"# gpsbabel XCSV style file\n" -"#\n" -"# Format: Ozi Explorer\n" -"# Author: Alex Mottram\n" -"# Date: 12/09/2002\n" -"#\n" -"# \n" -"# As used in ozi.c\n" -"# Modifications 9/18/2003 - Remove printf conversion constraints.\n" -"#\n" - -"DESCRIPTION OziExplorer Waypoint\n" -"EXTENSION ozi\n" -"SHORTLEN 14\n" - -"#\n" -"# FILE LAYOUT DEFINITIIONS:\n" -"#\n" -"FIELD_DELIMITER COMMA\n" -"RECORD_DELIMITER NEWLINE\n" -"BADCHARS COMMA\n" - -"PROLOGUE OziExplorer Waypoint File Version 1.1\n" -"PROLOGUE WGS 84\n" -"PROLOGUE Reserved 2\n" -"PROLOGUE Reserved 3\n" - -"#\n" -"# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:\n" -"#\n" -"IFIELD INDEX, \"1\", \"%d\"\n" -"IFIELD SHORTNAME, \"\", \"%s\"\n" -"IFIELD LAT_DECIMAL, \"\", \"%.6f\"\n" -"IFIELD LON_DECIMAL, \"\", \"%.6f\"\n" -"IFIELD EXCEL_TIME, \"\", \"%.5f\"\n" -"IFIELD CONSTANT, \"0\", \"%s\" # icon \n" -"IFIELD CONSTANT, \"1\", \"%s\" # 1 \n" -"IFIELD CONSTANT, \"3\", \"%s\" # display format opts \n" -"IFIELD CONSTANT, \"0\", \"%s\" # foreground color \n" -"IFIELD CONSTANT, \"65535\", \"%s\" # background color \n" -"IFIELD DESCRIPTION, \"\", \"%s\"\n" -"IFIELD CONSTANT, \"0\", \"%s\" # pointer direction \n" -"IFIELD CONSTANT, \"0\", \"%s\" # garmin display flags \n" -"IFIELD CONSTANT, \"0\", \"%s\" # proximity distance \n" -"IFIELD ALT_FEET, \"\", \"%.0f\"\n" -"IFIELD CONSTANT, \"6\", \"%s\" # waypt name text size \n" -"IFIELD CONSTANT, \"0\", \"%s\" # bold checkbox \n" -"IFIELD CONSTANT, \"17\", \"%s\" # symbol size \n" -; static char s_and_t[] = "# gpsbabel XCSV style file\n" "#\n" @@ -567,4 +517,4 @@ static char xmapwpt[] = "IFIELD DESCRIPTION, \"\", \"%-.78s\"\n" ; #include "defs.h" -style_vecs_t style_list[] = {{ "xmapwpt", xmapwpt } , { "xmap", xmap } , { "tabsep", tabsep } , { "s_and_t", s_and_t } , { "ozi", ozi } , { "nima", nima } , { "mxf", mxf } , { "mapconverter", mapconverter } , { "gpsman", gpsman } , { "gpsdrive", gpsdrive } , { "fugawi", fugawi } , { "dna", dna } , { "custom", custom } , { "csv", csv } , { "arc", arc } , {0,0}}; +style_vecs_t style_list[] = {{ "xmapwpt", xmapwpt } , { "xmap", xmap } , { "tabsep", tabsep } , { "s_and_t", s_and_t } , { "nima", nima } , { "mxf", mxf } , { "mapconverter", mapconverter } , { "gpsman", gpsman } , { "gpsdrive", gpsdrive } , { "fugawi", fugawi } , { "dna", dna } , { "custom", custom } , { "csv", csv } , { "arc", arc } , {0,0}}; diff --git a/gpsbabel/ozi.c b/gpsbabel/ozi.c new file mode 100644 index 000000000..e224a568f --- /dev/null +++ b/gpsbabel/ozi.c @@ -0,0 +1,618 @@ +/* + OziExplorer Waypoints/Tracks/Routes + Comma Delimited + + As described in OziExplorer Help File + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "csv_util.h" +#include +#include /* for floor */ + +#define MYNAME "OZI" + + +static FILE *file_in; +static FILE *file_out; +static void *mkshort_handle; +static route_head *trk_head; +static route_head *rte_head; + +static int route_out_count; +static int route_wpt_count; + +static char *snlenopt; +static char *snwhiteopt; +static char *snupperopt; +static char *snuniqueopt; + +static char *ozi_wpt_header = "OziExplorer Waypoint File Version 1.1\n" + "WGS 84\n" + "Reserved 2\n" + "Reserved 3\n"; + +static char *ozi_trk_header = "OziExplorer Track Point File Version 2.1\n" + "WGS 84\n" + "Altitude is in Feet\n" + "Reserved 3\n" + "0,2,255,ComplimentsOfGPSBabel,0,0,2,8421376\n" + "0\n"; + +static char *ozi_route_header = "OziExplorer Route File Version 1.0\n" + "WGS 84\n" + "Reserved 1\n" + "Reserved 2\n"; + +static +arglist_t ozi_args[] = { + {"snlen", &snlenopt, "Max synthesized shortname length", + ARGTYPE_INT}, + {"snwhite", &snwhiteopt, "(0/1) Allow whitespace synth. shortnames", + ARGTYPE_BOOL}, + {"snupper", &snupperopt, "(0/1) UPPERCASE synth. shortnames", + ARGTYPE_BOOL}, + {"snunique", &snuniqueopt, "(0/1) Make synth. shortnames unique", + ARGTYPE_BOOL}, + {0, 0, 0, 0} +}; + +static void +ozi_track_hdr(const route_head * rte) +{ + /* prologue at TOF only. */ + if (route_out_count == 0) + fprintf(file_out, ozi_trk_header); + + route_out_count++; +} + +static void +ozi_track_disp(const waypoint * waypointp) +{ + double alt_feet; + double ozi_time; + + ozi_time = (waypointp->creation_time / 86400.0) + 25569.0; + + if (waypointp->altitude == unknown_alt) { + alt_feet = -777; + } else { + alt_feet = (waypointp->altitude * 3.2808); + } + + fprintf(file_out, "%.6f,%.6f,0,%.0f,%.5f,,\n", + waypointp->latitude, waypointp->longitude, alt_feet, ozi_time); +} + +static void +ozi_track_tlr(const route_head * rte) +{ +} + +static void +ozi_track_pr() +{ + route_disp_all(ozi_track_hdr, ozi_track_tlr, ozi_track_disp); +} + +static void +ozi_route_hdr(const route_head * rte) +{ + /* prologue on 1st pass only */ + if (route_out_count == 0) { + fprintf(file_out, ozi_route_header); + } + + route_out_count++; + route_wpt_count = 0; + + /* + * Route Record + * Field 1 : R - indicating route details + * Field 2 : Number - this is the location in the array, must be unique, usually start at 0 for Garmins 1 for other and increment. + * Field 3 : Name - the waypoint name, use the correct length name to suit the GPS type. + * Field 4 : Description. + * Field 5 : Route Color as displayed on map (RGB). + * + * R, 0,R0 ,,255 + * R, 1, ICP GALHETA,, 16711680 + */ + + fprintf(file_out, "R,%d,%s,%s,\n", + route_out_count, + rte->rte_name ? rte->rte_name : "", + rte->rte_desc ? rte->rte_desc : ""); + +} + +static void +ozi_route_disp(const waypoint * waypointp) +{ + double alt_feet; + double ozi_time; + + route_wpt_count++; + + ozi_time = (waypointp->creation_time / 86400.0) + 25569.0; + + if (waypointp->altitude == unknown_alt) { + alt_feet = -777; + } else { + alt_feet = (waypointp->altitude * 3.2808); + } + +/* + * Field 1 : W - indicating route waypoint details. + * Field 2 : Route Number - location in array of routes + * Field 3 : Number - this is the location in the array of route waypoints, this field is now ignored. + * Field 4 : Wp Number - this is the number of the waypoint (the Wp number within the GPS for lowrances) + * Field 5 : Name - the waypoint name, use the correct length name to suit the GPS type. + * Field 6 : Latitude - decimal degrees. + * Field 7 : Longitude - decimal degrees. + * Field 8 : Date - see Date Format below, if blank a preset date will be used + * Field 9 : Symbol - 0 to number of symbols in GPS + * Field 10 : Status - always set to 1 + * Field 11 : Map Display Format + * Field 12 : Foreground Color (RGB value) + * Field 13 : Background Color (RGB value) + * Field 14 : Description (max 40), no commas + * Field 15 : Pointer Direction + * Field 16 : Garmin Display Format + * + * W,1,7,7,007,-25.581670,-48.316660,36564.54196,10,1,4,0,65535,TR ILHA GALHETA,0,0 + */ + + fprintf(file_out, "W,%d,%d,,%s,%.6f,%.6f,%.5f,0,1,3,0,65535,%s,0,0\n", + route_out_count, + route_wpt_count, + waypointp->shortname ? waypointp->shortname : "", + waypointp->latitude, + waypointp->longitude, + ozi_time, + waypointp->description ? waypointp->description : ""); + + +} + +static void +ozi_route_tlr(const route_head * rte) +{ +} + +static void +ozi_route_pr() +{ + route_disp_all(ozi_route_hdr, ozi_route_tlr, ozi_route_disp); +} + + +static void +rd_init(const char *fname) +{ + file_in = fopen(fname, "r"); + + if (file_in == NULL) { + fatal(MYNAME ": Cannot open %s for reading\n", fname); + } + + mkshort_handle = mkshort_new_handle(); + + switch (global_opts.objective) { + case trkdata: + trk_head = route_head_alloc(); + route_add_head(trk_head); + break; + case rtedata: + break; + case wptdata: + break; + default: + break; + + } +} + +static void +rd_deinit(void) +{ + fclose(file_in); + mkshort_del_handle(mkshort_handle); +} + +static void +wr_init(const char *fname) +{ + file_out = fopen(fname, "w"); + + if (file_out == NULL) { + fatal(MYNAME ": Cannot open %s for writing\n", fname); + } + + mkshort_handle = mkshort_new_handle(); + + /* set mkshort options from the command line if applicable */ + if (global_opts.synthesize_shortnames) { + + if (snlenopt) + setshort_length(mkshort_handle, atoi(snlenopt)); + else + setshort_length(mkshort_handle, 32); + + if (snwhiteopt) + setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt)); + + if (snupperopt) + setshort_mustupper(mkshort_handle, atoi(snupperopt)); + + if (snuniqueopt) + setshort_mustuniq(mkshort_handle, atoi(snuniqueopt)); + + setshort_badchars(mkshort_handle, "\","); + } + +} + +static void +wr_deinit(void) +{ + fclose(file_out); + mkshort_del_handle(mkshort_handle); +} + +static void +ozi_parse_waypt(int field, char *str, waypoint * wpt_tmp) +{ + double alt; + + switch (field) { + case 0: + /* sequence # */ + break; + case 1: + /* waypoint name */ + wpt_tmp->shortname = csv_stringtrim(str, "", 0); + break; + case 2: + /* degrees latitude */ + wpt_tmp->latitude = atof(str); + break; + case 3: + /* degrees longitude */ + wpt_tmp->longitude = atof(str); + break; + case 4: + /* DAYS since 1900 00:00:00 in days.days (5.5) */ + wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0; + break; + case 5: + /* icons 0-xx */ + break; + case 6: + /* unknown - always 1 */ + break; + case 7: + /* display format options 0-8 */ + break; + case 8: + /* foreground color (0=black) */ + break; + case 9: + /* background color (65535=yellow) */ + break; + case 10: + /* Description */ + wpt_tmp->description = csv_stringtrim(str, "", 0); + break; + case 11: + /* pointer direction 0,1,2,3 bottom,top,left,right */ + break; + case 12: + /* garmin gps display flags (0-name w/sym, 1-sym only, 2-comment w/symbol */ + break; + case 13: + /* proximity distance - meters */ + break; + case 14: + /* altitude in feet */ + alt = atof(str); + if (alt == -777) { + wpt_tmp->altitude = unknown_alt; + } else { + wpt_tmp->altitude = alt * .3048; + } + break; + case 15: + /* waypoint text name size */ + break; + case 16: + /* bold checkbox (1=bold, default 0) */ + break; + case 17: + /* symbol size - 17 default */ + break; + /* + * Fields 18-23 were added around version 3.90.4g of + * Ozi, but aren't documented. We silently ignore + * these or any additional fields we don't need. + */ + default: + break; + } +} + +static void +ozi_parse_track(int field, char *str, waypoint * wpt_tmp) +{ + double alt; + + switch (field) { + case 0: + /* latitude */ + wpt_tmp->latitude = atof(str); + break; + case 1: + /* longitude */ + wpt_tmp->longitude = atof(str); + break; + case 2: + /* ignore */ + break; + case 3: + /* altitude in feet */ + alt = atof(str); + if (alt == -777) { + wpt_tmp->altitude = unknown_alt; + } else { + wpt_tmp->altitude = alt * .3048; + } + break; + case 4: + /* DAYS since 1900 00:00:00 in days.days (5.5) */ + wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0; + break; + default: + break; + } +} + +static void +ozi_parse_routepoint(int field, char *str, waypoint * wpt_tmp) +{ + + switch (field) { + case 0: + /* W */ + break; + case 1: + /* route # */ + break; + case 2: + /* waypoint # -- ignored by ozi */ + break; + case 3: + /* waypoint # */ + break; + case 4: + /* waypoint name */ + wpt_tmp->shortname = csv_stringclean(str, ","); + break; + case 5: + /* latitude */ + wpt_tmp->latitude = atof(str); + break; + case 6: + /* longitude */ + wpt_tmp->longitude = atof(str); + break; + case 7: + /* DAYS since 1900 00:00:00 in days.days (5.5) */ + wpt_tmp->creation_time = (atof(str) - 25569.0) * 86400.0; + break; + default: + break; + } +} + +static void +ozi_parse_routeheader(int field, char *str, waypoint * wpt_tmp) +{ + + switch (field) { + case 0: + /* R */ + rte_head = route_head_alloc(); + route_add_head(rte_head); + break; + case 1: + /* route # */ + rte_head->rte_num = atoi(str); + break; + case 2: + /* route name */ + rte_head->rte_name = csv_stringclean(str, ","); + break; + case 3: + /* route description */ + rte_head->rte_desc = csv_stringclean(str, ","); + break; + case 4: + /* route color */ + break; + default: + break; + } +} + +static void +data_read(void) +{ + char buff[1024]; + char *s; + waypoint *wpt_tmp; + int i; + int linecount = 0; + + do { + linecount++; + memset(buff, '\0', sizeof(buff)); + fgets(buff, sizeof(buff), file_in); + + if ((strlen(buff)) && (strstr(buff, ",") != NULL)) { + + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); + + /* data delimited by commas, possibly enclosed in quotes. */ + s = buff; + s = csv_lineparse(s, ",", "", linecount); + + i = 0; + while (s) { + switch (global_opts.objective) { + case trkdata: + ozi_parse_track(i, s, wpt_tmp); + break; + case rtedata: + if (buff[0] == 'R') { + ozi_parse_routeheader(i, s, wpt_tmp); + } else { + ozi_parse_routepoint(i, s, wpt_tmp); + } + + break; + case wptdata: + ozi_parse_waypt(i, s, wpt_tmp); + break; + } + i++; + s = csv_lineparse(NULL, ",", "", linecount); + } + + switch (global_opts.objective) { + case trkdata: + if (linecount > 6) /* skipping over file header */ + route_add_wpt(trk_head, wpt_tmp); + else + waypt_free(wpt_tmp); + break; + case rtedata: + if (linecount > 5) /* skipping over file header */ + route_add_wpt(rte_head, wpt_tmp); + else + waypt_free(wpt_tmp); + break; + case wptdata: + if (linecount > 4) /* skipping over file header */ + waypt_add(wpt_tmp); + else + waypt_free(wpt_tmp); + break; + } + + } else { + /* empty line */ + } + + } while (!feof(file_in)); +} + +static void +ozi_waypt_pr(const waypoint * wpt) +{ + static int index = 0; + double alt_feet; + double ozi_time; + char *description; + char *shortname; + + ozi_time = (wpt->creation_time / 86400.0) + 25569.0; + + if (wpt->altitude == unknown_alt) { + alt_feet = -777; + } else { + alt_feet = (wpt->altitude * 3.2808); + } + + if ((!wpt->shortname) || (global_opts.synthesize_shortnames)) { + if (wpt->description) { + if (global_opts.synthesize_shortnames) + shortname = mkshort(mkshort_handle, wpt->description); + else + shortname = csv_stringclean(wpt->description, ","); + } else { + /* no description available */ + shortname = xstrdup(""); + } + } else { + shortname = csv_stringclean(wpt->shortname, ","); + } + + if (!wpt->description) { + if (shortname) { + description = csv_stringclean(shortname, ","); + } else { + description = xstrdup(""); + } + } else { + description = csv_stringclean(wpt->description, ","); + } + + index++; + + fprintf(file_out, + "%d,%s,%.6f,%.6f,%.5f,%d,%d,%d,%d,%d,%s,%d,%d,%d,%.0f,%d,%d,%d\n", + index, shortname, wpt->latitude, wpt->longitude, ozi_time, 0, + 1, 3, 0, 65535, description, 0, 0, 0, alt_feet, 6, 0, 17); + + free(description); + free(shortname); + +} + +static void +data_write(void) +{ + + switch (global_opts.objective) { + case trkdata: + ozi_track_pr(); + break; + case rtedata: + route_out_count = 0; + ozi_route_pr(); + break; + case wptdata: + fprintf(file_out, ozi_wpt_header); + waypt_disp_all(ozi_waypt_pr); + break; + default: + break; + } +} + +ff_vecs_t ozi_vecs = { + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + ozi_args +}; diff --git a/gpsbabel/vecs.c b/gpsbabel/vecs.c index 5f56728b9..4a828dd3f 100644 --- a/gpsbabel/vecs.c +++ b/gpsbabel/vecs.c @@ -57,6 +57,7 @@ extern ff_vecs_t navicache_vecs; extern ff_vecs_t psit_vecs; /* MRCB */ extern ff_vecs_t geoniche_vecs; extern ff_vecs_t gpl_vecs; +extern ff_vecs_t ozi_vecs; static vecs_t vec_list[] = { @@ -223,6 +224,12 @@ vecs_t vec_list[] = { "Delorme GPL", NULL }, + { + &ozi_vecs, + "ozi", + "OziExplorer", + NULL + }, { NULL, NULL, -- 2.30.2